In [1]:
# Required Packages
import pandas as pd
from pandas import Series, DataFrame
import numpy as np
import pandas_datareader.data as pdr
from datetime import datetime
import math

# Progress Bar
from IPython.core.display import Image, display
import progressbar

# Plots
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib as mpl

# sns setting
sns.set_context("paper", rc={"font.size":12,"axes.titlesize":14,"axes.labelsize":12})

# plt setting
sns.set_style('whitegrid')
mpl.rcParams['axes.labelsize'] = 14
mpl.rcParams['xtick.labelsize'] = 12
mpl.rcParams['ytick.labelsize'] = 12
mpl.rcParams['text.color'] = 'k'
%matplotlib inline
import warnings
warnings.filterwarnings("ignore")

The Market Analysis for Technology Services Sector

In this article, the Technology Services Sector data from Yahoo! Finance is used, and we analyze the current top tech companies' stock prices.

Table of contentens

Symbol Name
AAPL Apple Inc.
MSFT Microsoft Corporation
TSM Taiwan Semiconductor Manufacturing Company Limited
INTC Intel Corporation
CSCO Cisco Systems, Inc.
ORCL Oracle Corporation
SAP SAP SE
ADBE Adobe Inc.
CRM salesforce.com, inc.
NVDA NVIDIA Corporation
ACN Accenture plc
AVGO Broadcom Inc.
IBM International Business Machines Corporation
ASML ASML Holding N.V.
TXN Texas Instruments Incorporated
QCOM QUALCOMM Incorporated
FIS Fidelity National Information Services, Inc.
SNE Sony Corporation
INTU Intuit Inc.
VMW VMware, Inc.
AMAT Applied Materials, Inc.
MU Micron Technology, Inc.
NOW ServiceNow, Inc.
UBER Uber Technologies, Inc.
AMD Advanced Micro Devices, Inc.
In [2]:
Tech_list = ['AAPL','MSFT','TSM','INTC','CSCO','ORCL','SAP','ADBE','CRM',
             'NVDA','ACN','AVGO','IBM','ASML','TXN','QCOM','FIS','SNE','INTU','VMW','AMAT','MU','NOW','UBER','AMD']
Tech_Dic = {'AAPL':'Apple Inc.',
            'MSFT':'Microsoft Corporation',
            'TSM':'Taiwan Semiconductor Manufacturing Company Limited',
            'INTC':'Intel Corporation',
            'CSCO':'Cisco Systems, Inc.',
            'ORCL':'Oracle Corporation',
            'SAP':'SAP SE',
            'ADBE':'Adobe Inc.',
            'CRM':'salesforce.com, inc.',
            'NVDA':'NVIDIA Corporation',
            'ACN':'Accenture plc',
            'AVGO':'Broadcom Inc.',
            'IBM':'International Business Machines Corporation',
            'ASML':'ASML Holding N.V.',
            'TXN':'Texas Instruments Incorporated',
            'QCOM':'QUALCOMM Incorporated',
            'FIS':'Fidelity National Information Services, Inc.',
            'SNE':'Sony Corporation',
            'INTU':'Intuit Inc.',
            'VMW':'VMware, Inc.',
            'AMAT':'Applied Materials, Inc.',
            'MU':'Micron Technology, Inc.',
            'NOW':'ServiceNow, Inc.',
            'UBER':'Uber Technologies, Inc.',
            'AMD':'Advanced Micro Devices, Inc.'}

The data is collected from a year before today until now.

In [3]:
start, end = [datetime(datetime.today().year-1,datetime.today().month,datetime.today().day), datetime.today()]
start, end
Out[3]:
(datetime.datetime(2018, 11, 28, 0, 0),
 datetime.datetime(2019, 11, 28, 8, 5, 24, 304633))

Collecting data from Yahoo Finance!, and creating moving averages for 10, 20 and 60 day periods of time.

In [4]:
def Get_Data(Inp):
    Days = [10, 20, 60]
    Out = pdr.DataReader(Inp, 'yahoo', start, end)
    Out.insert(0, 'Symbol', Inp) 
    for j in Days:
        column_name = "Moving Ave. %s days" % (str(j))
        Out[column_name] = Out['Adj Close'].rolling(window=j, center=False).mean()
    return Out
In [5]:
Data = Get_Data(Tech_list[0])

Counter = 0
Progress_Bar = progressbar.ProgressBar(maxval=len(Tech_list),
                                       widgets=[progressbar.Bar('#', '|', '|'), progressbar.Percentage()])
Progress_Bar.start()
for i in Tech_list[1:]:
    Counter+=1
    Progress_Bar.update(Counter)
    Temp = Get_Data(i)
    Data = pd.concat([Data, Temp])
    del Temp
Progress_Bar.finish()
|#########################################################################|100%

Displaying today's data only:

In [6]:
Today = Data[Data.index == datetime.today().strftime('%Y-%m-%d')].reset_index(drop = True)
Today.style.hide_index()
Out[6]:
Symbol High Low Open Close Volume Adj Close Moving Ave. 10 days Moving Ave. 20 days Moving Ave. 60 days

Consider Apple Inc. for example. We have,

In [7]:
def Disp_Data(Inp):
    Out = Data[Data.Symbol == Inp].drop(columns=['Symbol'])
    return Out
In [8]:
Temp = Disp_Data('AAPL')
Temp.describe()
Out[8]:
High Low Open Close Volume Adj Close Moving Ave. 10 days Moving Ave. 20 days Moving Ave. 60 days
count 252.000000 252.000000 252.000000 252.000000 2.520000e+02 252.000000 243.000000 233.000000 193.000000
mean 200.387024 196.702024 198.462261 198.675953 2.968718e+07 197.221529 196.368602 195.597421 194.867322
std 29.029203 29.111273 29.045371 29.177472 1.224544e+07 29.775750 28.418790 26.551655 18.855466
min 145.720001 142.000000 143.979996 142.190002 1.136200e+07 140.085220 148.423929 150.503188 160.895787
25% 177.877499 174.382504 175.572506 175.415001 2.113860e+07 173.832317 173.894009 178.248456 186.433787
50% 200.675003 198.019997 199.000000 199.239998 2.644210e+07 197.412338 198.010825 197.581352 193.982851
75% 214.082500 210.427505 212.247501 211.927502 3.479432e+07 210.197338 207.164536 206.641606 206.681554
max 268.000000 265.390015 267.899994 267.839996 9.574460e+07 267.839996 264.727005 261.404964 238.477948
In [9]:
Temp.head().dropna(axis = 1)
Out[9]:
High Low Open Close Volume Adj Close
Date
2018-11-28 181.289993 174.929993 176.729996 180.940002 46062500.0 178.261627
2018-11-29 182.800003 177.699997 182.660004 179.550003 41770000.0 176.892197
2018-11-30 180.330002 177.029999 180.289993 178.580002 39531500.0 175.936554
2018-12-03 184.940002 181.210007 184.460007 184.820007 40802500.0 182.084183
2018-12-04 182.389999 176.270004 180.949997 176.690002 41344300.0 174.074539
In [10]:
Temp.tail()
Out[10]:
High Low Open Close Volume Adj Close Moving Ave. 10 days Moving Ave. 20 days Moving Ave. 60 days
Date
2019-11-21 264.010010 261.179993 263.690002 262.010010 30348800.0 262.010010 263.576007 257.352966 234.642410
2019-11-22 263.179993 260.839996 262.589996 261.779999 16331300.0 261.779999 263.740005 258.149870 235.532337
2019-11-25 266.440002 262.519989 262.709991 266.369995 21005100.0 266.369995 264.157004 259.053143 236.503250
2019-11-26 267.160004 262.500000 266.940002 264.290009 26301900.0 264.290009 264.390005 260.139556 237.490012
2019-11-27 267.980011 265.309998 265.579987 267.839996 16308900.0 267.839996 264.727005 261.404964 238.477948

Stock Prices Fluctuations

Let's plot the stocks adjusted the closing price for all stock data under study.

In [11]:
def get_ylim(Inp, Var):
    Temp = int(np.float(format(Inp[Var].max(), '.0e')))
    Out = Temp + Temp/(Temp/10**(len(str(Temp))-1))/2
    return Out
In [12]:
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(18, 12))
for i in range(len(Tech_list)):
    Data[Data.Symbol == Tech_list[i]]['Adj Close'].plot(ax=ax, label=Tech_Dic[Tech_list[i]])
_ = ax.legend(loc='upper center', bbox_to_anchor=(1.2, 0.9), shadow=True, ncol=1, fontsize=12)
_ = ax.set_ylim([0, get_ylim(Data, 'Adj Close')])

We can create some new functions that can be beneficial for applications as well.

In [13]:
def List_Search(Inp, key):
    # Inp: A list
    Out=list()
    for i in range(len(Inp)):
        if Inp[i].find(key) != -1:
            Out.append(Inp[i])
    return Out

def List_Diff(Inp_A, Inp_B):
    # Inp_A: A list
    # Inp_B: A list
    Out=list(set(Inp_A)-set(Inp_B))
    return Out
In [14]:
# Creating a new list of Columns
Columns = List_Diff(Data.columns.tolist(), List_Search(Data.columns.tolist(), 'Moving Ave'))
Columns = List_Diff(Columns, ['Symbol'])
Temp = ['Ave ' + i for i in Columns]

# A new DataFrame
Ave_df = pd.DataFrame({'Symbol':Tech_list})
for i in Temp:
    Ave_df[i]=''
del Temp
# Progress Bar    
Counter = 0
Progress_Bar = progressbar.ProgressBar(maxval=len(Tech_list),
                                       widgets=[progressbar.Bar('#', '|', '|'), progressbar.Percentage()])
Progress_Bar.start()
for i in range(len(Tech_list)):
    Counter+=1
    Progress_Bar.update(Counter)
    Ave_df.iloc[i,1:] = Data[Data.Symbol == Tech_list[i]][Columns].mean().values
               
Progress_Bar.finish()
|#########################################################################|100%
In [15]:
Ave_df.style.hide_index()
Out[15]:
Symbol Ave Open Ave Adj Close Ave Low Ave High Ave Close Ave Volume
AAPL 198.462 197.222 196.702 200.387 198.676 2.96872e+07
MSFT 126.127 125.145 124.968 127.085 126.122 2.69247e+07
TSM 42.0754 41.1914 41.7676 42.4156 42.1063 7.87029e+06
INTC 50.3862 49.7748 49.9049 50.9181 50.4395 2.28216e+07
CSCO 50.5308 49.8701 50.0608 50.9656 50.5131 2.15614e+07
ORCL 53.1604 52.7455 52.735 53.622 53.1773 1.4384e+07
SAP 118.718 118.064 117.996 119.402 118.733 777702
ADBE 272.098 272.11 268.931 274.813 272.11 2.89756e+06
CRM 152.9 152.875 150.939 154.553 152.875 5.92156e+06
NVDA 167.761 167.379 165.087 170.37 167.746 1.21887e+07
ACN 176.826 175.843 175.517 178.164 176.96 1.97655e+06
AVGO 281.261 277.097 278.004 284.519 281.383 2.79972e+06
IBM 135.555 132.119 134.499 136.577 135.588 3.9935e+06
ASML 207.433 205.877 205.717 209.178 207.512 706444
TXN 112.979 111.425 111.844 114.118 113.012 5.21589e+06
QCOM 69.0881 68.3115 68.2954 70.08 69.1658 1.42303e+07
FIS 119.971 119.454 118.806 120.995 119.973 3.32347e+06
SNE 52.3223 52.2761 51.9431 52.7006 52.3419 1.30881e+06
INTU 250.592 249.796 247.823 253.137 250.668 1.45582e+06
VMW 166.49 164.326 164.266 168.689 166.553 1.38606e+06
AMAT 43.9668 43.5976 43.4263 44.5763 44.0071 9.60634e+06
MU 41.0278 41.0421 40.3914 41.7269 41.0421 2.77257e+07
NOW 246.16 246.207 242.448 249.59 246.207 2.17868e+06
UBER 36.6149 36.5024 35.8201 37.2264 36.5024 1.7298e+07
AMD 27.9694 27.9635 27.4096 28.5118 27.9635 7.13736e+07
In [16]:
fig, ax = plt.subplots(nrows=2, ncols=1, figsize=(18, 14), sharex=False)
# Upper Plot
Ave_df.plot.bar(x='Symbol', y='Ave Volume', rot=90,ax=ax[0], legend=False ,color='#34495e', edgecolor='k')
_ = ax[0].set_ylim([0, get_ylim(Ave_df, 'Ave Volume')])
# Lower Plot
Temp = Ave_df.drop(columns=['Ave Volume'])
Temp.plot.bar(x='Symbol', rot=90,ax=ax[1], legend=True, edgecolor='k')
_ = ax[1].set_ylim([0, get_ylim(Ave_df, 'Ave High')])
_ = ax[1].legend(loc='upper center', bbox_to_anchor=(0.5, -0.2), shadow=True, ncol=len(Temp.columns)-1, fontsize=12)
# Plot setting
plt.subplots_adjust(hspace=0.3,wspace=0.2)

The Moving Average of the Stocks

Let's plot moving averages for 10, 20 and 60 day periods of time for the top 4 companies with the highest volume on average.

In [17]:
def TopN_volumes(N, df = Ave_df):
    Out = df.sort_values(by='Ave Volume', ascending=False).iloc[:N,0].tolist()
    return Out 

# Conisder the Moving Ave and Adj Close columns
Columns = List_Search(Data.columns.tolist(), 'Moving Ave')
Columns.append("Adj Close")
Columns = list(np.sort(Columns))
# A list of top N = 4 companies with the hightest volume on average.
N = 4
mylist = TopN_volumes(N)
In [18]:
# Conisder the Moving Ave and Adj Close columns
Columns = List_Search(Data.columns.tolist(), 'Moving Ave')
Columns.append("Adj Close")
Columns = list(np.sort(Columns))
# A list of top N = 4 companies with the hightest volume on average.
N = 4
mylist = Ave_df.sort_values(by='Ave Volume', ascending=False).iloc[:N,0].tolist()
In [19]:
fig, ax = plt.subplots(nrows = math.ceil(N/2), ncols = 2, figsize=(16, 6*math.ceil(N/2)))

Counter = 0
for i in range(math.ceil(N/2)):
    for j in range(2):
        Disp_Data(mylist[Counter])[Columns].plot(ax=ax[i,j], legend = True)
        _ = ax[i,j].set_title(Tech_Dic[mylist[Counter]])
        _ = ax[i,j].legend(loc='upper center', bbox_to_anchor=(0.5, -0.25), shadow=True, ncol=2, fontsize=12)
        Counter += 1
plt.subplots_adjust(hspace=0.6, wspace=0.2)

The Daily Return Average of a Stock

Daily return can be calculated using the percentage change of the adjusted closing price.

In [20]:
fig, ax = plt.subplots(nrows = 1, ncols = 1, figsize=(16, 10))
for i in range(len(mylist)):
    Disp_Data(mylist[i])['Adj Close'].pct_change().plot(ax=ax, label=Tech_Dic[mylist[i]])
_ = ax.legend(loc='upper center', bbox_to_anchor=(1.15, 0.9), shadow=True, ncol=1, fontsize=12)
_ = ax.set_ylim([-0.15 , 0.25])
_ = ax.set_title('Daily Return', fontsize=14)

The Correlation Between Daily Returns of Different Stocks

First, we need to create a new data frame by reading the Adj Close column from all stock data under study. We have,

In [21]:
All_data = pdr.DataReader(Tech_list, 'yahoo', start, end)['Adj Close']
In [22]:
All_data.head()
Out[22]:
Symbols AAPL MSFT TSM INTC CSCO ORCL SAP ADBE CRM NVDA ... QCOM FIS SNE INTU VMW AMAT MU NOW UBER AMD
Date
2018-11-28 178.261627 109.500916 36.551834 47.670719 45.990639 47.381966 103.499786 249.210007 140.639999 159.287933 ... 54.463261 106.680695 52.684010 207.279938 132.716400 36.442188 38.709999 177.869995 NaN 21.340000
2018-11-29 176.892197 108.584465 36.474907 46.538952 46.039261 47.096836 102.592148 249.089996 139.720001 156.747833 ... 55.866898 104.605385 51.658409 207.547821 134.145233 35.882442 37.910000 179.100006 NaN 21.430000
2018-11-30 175.936554 109.274261 36.147949 48.109768 46.554695 47.942413 102.286316 250.889999 142.759995 162.794220 ... 56.011108 106.680695 52.594395 212.845901 139.013275 36.609127 38.560001 185.270004 NaN 21.299999
2018-12-03 182.084183 110.456779 37.244213 48.909809 47.400795 48.994476 103.874680 255.259995 144.149994 169.378494 ... 56.857140 107.836945 53.938625 211.843826 135.931305 37.650051 40.029999 188.089996 NaN 23.709999
2018-12-04 174.074539 106.938789 36.003704 46.587734 46.048985 47.932579 101.526672 245.820007 139.240005 156.498795 ... 55.501568 104.872215 51.289989 206.019913 131.686310 34.792416 36.880001 180.850006 NaN 21.120001

5 rows × 25 columns

In [23]:
All_data.tail()
Out[23]:
Symbols AAPL MSFT TSM INTC CSCO ORCL SAP ADBE CRM NVDA ... QCOM FIS SNE INTU VMW AMAT MU NOW UBER AMD
Date
2019-11-21 262.010010 149.479996 52.980000 58.220001 44.840000 56.230000 135.429993 298.799988 162.880005 210.025024 ... 85.110001 136.470001 61.520000 271.149994 165.699997 56.439999 45.549999 279.119995 29.459999 39.520000
2019-11-22 261.779999 149.589996 52.790001 57.610001 44.849998 56.389999 135.410004 299.299988 162.809998 210.734512 ... 84.889999 135.460007 61.200001 259.809998 165.860001 55.939999 45.869999 279.980011 29.559999 39.150002
2019-11-25 266.369995 151.229996 53.759998 58.810001 45.450001 56.560001 135.740005 305.279999 161.710007 221.046906 ... 85.290001 136.880005 61.799999 257.070007 168.729996 58.279999 47.520000 279.750000 29.110001 39.790001
2019-11-26 264.290009 152.029999 53.630001 58.900002 45.310001 56.509998 135.339996 307.899994 162.539993 216.839996 ... 84.629997 137.539993 63.150002 265.880005 164.899994 57.570000 46.720001 278.859985 29.530001 38.990002
2019-11-27 267.839996 152.320007 53.889999 58.509998 45.240002 56.610001 135.410004 309.059998 161.509995 218.240005 ... 84.800003 138.429993 63.720001 262.149994 161.149994 58.290001 48.160000 281.279999 29.490000 39.410000

5 rows × 25 columns

The returns can be analyzed using the percentage change from the adj Close.

In [24]:
All_returns = All_data.pct_change()
In [25]:
All_returns.tail()
Out[25]:
Symbols AAPL MSFT TSM INTC CSCO ORCL SAP ADBE CRM NVDA ... QCOM FIS SNE INTU VMW AMAT MU NOW UBER AMD
Date
2019-11-21 -0.004483 -0.000936 -0.009720 0.005527 -0.005324 -0.000178 0.003185 -0.004332 -0.008039 -0.004735 ... -0.005957 -0.007274 0.000651 -0.008520 -0.023110 -0.053814 -0.000439 -0.013710 0.051017 -0.035627
2019-11-22 -0.000878 0.000736 -0.003586 -0.010478 0.000223 0.002845 -0.000148 0.001673 -0.000430 0.003378 ... -0.002585 -0.007401 -0.005202 -0.041822 0.000966 -0.008859 0.007025 0.003081 0.003394 -0.009362
2019-11-25 0.017534 0.010963 0.018375 0.020830 0.013378 0.003015 0.002437 0.019980 -0.006756 0.048935 ... 0.004712 0.010483 0.009804 -0.010546 0.017304 0.041831 0.035971 -0.000822 -0.015223 0.016347
2019-11-26 -0.007809 0.005290 -0.002418 0.001530 -0.003080 -0.000884 -0.002947 0.008582 0.005133 -0.019032 ... -0.007738 0.004822 0.021845 0.034271 -0.022699 -0.012183 -0.016835 -0.003181 0.014428 -0.020106
2019-11-27 0.013432 0.001908 0.004848 -0.006621 -0.001545 0.001770 0.000517 0.003767 -0.006337 0.006456 ... 0.002009 0.006471 0.009026 -0.014029 -0.022741 0.012507 0.030822 0.008678 -0.001355 0.010772

5 rows × 25 columns

In [26]:
fig, ax = plt.subplots(nrows = 1, ncols = 1, figsize=(16, 10))
All_returns.plot(marker='*', legend=True, ax=ax)
_ = ax.set_ylim([-0.15 , 0.25])
_ = ax.set_title('Daily Returns', fontsize=14)
_ = ax.legend(Tech_Dic.values(), loc='upper center', bbox_to_anchor=(1.2, 0.9), shadow=True, ncol=1, fontsize=12)

We can see that most high returns happen around the same time. However, it is needed to analyze this more carefully. Using a joinplot, we can investigate the correlation between different data. For example, we can plot a joinplot for Apple Inc. and Microsoft Corporation, and Apple Inc. and Alphabet Inc.;

In [27]:
_ = sns.jointplot('AAPL','MSFT', All_returns, kind='reg', space=0, size=6, ratio=4)
_ = sns.jointplot('AAPL','AMD', All_returns, kind='reg', space=0, size=6, ratio=4)

There seems to be a minor positive correlation between every two pairs. In particular, the return for Apple Inc. and Microsoft Corporation are highly correlated.

Now, we can use the pairplot tool to visualize all.

In [28]:
# Remove missing values
Temp = TopN_volumes(8, df = Ave_df)
Temp = All_returns[Temp].dropna()
# plot
_ = sns.pairplot(Temp, diag_kind='kde')

Nonetheless, the correlation matrix and plot are always convenient to see numerical values for correlations.

In [29]:
# Correlation Matrix
Cor_matrix = Temp.corr()
Cor_matrix
Out[29]:
Symbols AMD AAPL MU MSFT INTC CSCO UBER ORCL
Symbols
AMD 1.000000 0.506825 0.472265 0.596593 0.403798 0.380577 0.363388 0.413012
AAPL 0.506825 1.000000 0.554499 0.643811 0.667289 0.562807 0.347306 0.560629
MU 0.472265 0.554499 1.000000 0.523548 0.626575 0.313078 0.263963 0.471284
MSFT 0.596593 0.643811 0.523548 1.000000 0.621192 0.571597 0.394994 0.589620
INTC 0.403798 0.667289 0.626575 0.621192 1.000000 0.500315 0.266419 0.513105
CSCO 0.380577 0.562807 0.313078 0.571597 0.500315 1.000000 0.347257 0.467401
UBER 0.363388 0.347306 0.263963 0.394994 0.266419 0.347257 1.000000 0.261808
ORCL 0.413012 0.560629 0.471284 0.589620 0.513105 0.467401 0.261808 1.000000
In [30]:
def Correlation_Plot (Df,Fig_Size):
    Correlation_Matrix = Df.corr()
    mask = np.zeros_like(Correlation_Matrix)
    mask[np.triu_indices_from(mask)] = True
    for i in range(len(mask)):
        mask[i,i]=0
    Fig, ax = plt.subplots(figsize=(Fig_Size,Fig_Size))
    sns.heatmap(Correlation_Matrix, ax=ax, mask=mask, annot=True, square=True, 
                cmap =sns.color_palette("RdBu", n_colors=10), linewidths = 0.2, vmin=0, vmax=1, cbar_kws={"shrink": .5})
    bottom, top = ax.get_ylim()
    _ = ax.set_ylim(bottom + 0.5, top - 0.5)
In [31]:
Correlation_Plot (Temp, 8)

Here, darker shades of blue represent a higher correlation.

In [32]:
def Risk_Plot(data):
    fig, ax = plt.subplots(nrows = 1, ncols = 1, figsize=(16, 6))
    _ = ax.scatter(data.mean(), data.std(), s=25, color = "#e74c3c")
    _ = ax.set_xlabel('Expected Return')
    _ = ax.set_ylabel('Risk')
    _ = ax.set_xlim([np.float(format(data.mean().min(), '.0e')), np.float(format(data.mean().max(), '.0e'))])
    _ = ax.set_ylim([np.float(format(data.std().min(), '.0e')), np.float(format(data.std().max(), '.0e'))])
    # adding annotatios
    for label,x,y in zip(data.columns, data.mean(), data.std()):
        plt.annotate(label, xy=(x,y), xytext=(-50,0), textcoords = 'offset points',
                     ha = 'right', va = 'bottom', arrowprops=dict(facecolor="#9b59b6", shrink=0.001))
In [33]:
Risk_Plot(All_returns)

The current trend to output a value between 0 and 0.002. We would like to identify a crypto with high return and low risk!

In [34]:
qt = All_returns['AAPL'].quantile(0.05)
In [35]:
qt_pct = abs(All_returns['AAPL'].quantile(0.05))*100
print(qt_pct)
2.5554327757444706
In [36]:
print("""The 0.05 empirical quantile of daily returns is at {0:.2f}.
      This means that with 95% confidence, the worst daily loss will not exceed {0:.2f}% (of the investment)."""
      .format(qt,qt_pct))
The 0.05 empirical quantile of daily returns is at -0.03.
      This means that with 95% confidence, the worst daily loss will not exceed -0.03% (of the investment).

Predicting Future Behaviors

To predict future behaviors, we can implement the Monte Carlo method (also see this link and this link).

In [37]:
# consider a year
days = 365
# Delta t
dt = 1/365

Defining a Monte Carlo function fo the Stock price.

In [38]:
def stock_monte_carlo(start_price, days, mu, sigma):
    '''Function takes in stock price, number of days to run, mean and standard deviation values'''
    price = np.zeros(days)
    price[0] = start_price
    
    shock = np.zeros(days)
    drift = np.zeros(days)
    
    for x in range(1,days):       
        #Shock and drift formulas taken from the Monte Carlo formula
        shock[x] = np.random.normal(loc=mu*dt,scale=sigma*np.sqrt(dt))        
        drift[x] = mu * dt
        #New price = Old price + Old price*(shock+drift)
        price[x] = price[x-1] + (price[x-1] * (drift[x]+shock[x]))
    return price
In [39]:
def Monte_Carlo_Analysis(Inp, mu, sigma, N=1e2, days = days):
    # get the data for Inp teach
    df = Disp_Data(Inp)
    # set the last entry of the open column as the starting price
    start_price = df['Open'][-1]
    # Ouput Figure
    N = int(N)
    fig, ax = plt.subplots(nrows = 1, ncols = 1, figsize=(16, 8))
    for run in range(100):
        _ = plt.plot(stock_monte_carlo(start_price, days, mu, sigma))
        _ = ax.set_xlabel('Days')
        _ = ax.set_ylabel('Price')
        _ = ax.set_title('Monte Carlo Analysis for %s' % Tech_Dic[Inp])
    _ = ax.set_xlim([0,days])
    return df
In [40]:
def Final_price_distribution_simulations(Inp, mu, sigma, N= 1e4, days = days):
    # get the data for Inp teach
    df = Disp_Data(Inp)
    # set the last entry of the open column as the starting price
    start_price = df['Open'][-1]
    # Simulations array
    N = int(N)
    simulations = np.zeros(N)
    # Progress Bar    
    Counter = 0
    Progress_Bar = progressbar.ProgressBar(maxval= N, widgets=[progressbar.Bar('#', '|', '|'), progressbar.Percentage()])
    Progress_Bar.start()

    for i in range(N):
        simulations[i] = stock_monte_carlo(start_price, days, mu, sigma)[days-1]
        Counter+=1
        Progress_Bar.update(Counter)
    Progress_Bar.finish()
    return simulations
In [41]:
def Final_price_distribution_plot(simulations, Inp):
    # get the data for Inp teach
    df = Disp_Data(Inp)
    # set the last entry of the open column as the starting price
    start_price = df['Open'][-1]
    # Output Figure
    fig, ax = plt.subplots(nrows = 1, ncols = 1, figsize=(16, 8))
    q = np.percentile(simulations, 1)
    _ = ax.hist(simulations, bins='auto', color = '#34495e')
    _ = plt.figtext(0.75, 0.80, s="Start price: $%.2f" % start_price, fontsize = 12)
    _ = plt.figtext(0.75, 0.75, "Mean final price: $%.2f" % simulations.mean(), fontsize = 12)
    _ = plt.figtext(0.75, 0.70, "VaR(0.99): $%.2f" % (start_price -q,), fontsize = 12)
    _ = plt.figtext(0.15,0.665, "q(0.99): $%.2f" % q, fontsize = 12)
    _ = ax.set_xlim()
    _ = ax.axvline(x=q, linewidth=4, color='#e74c3c')
    _ = ax.set_title("Final price distribution for %s after %s days" % (Tech_Dic[Inp], days), weight='bold')

Advanced Micro Devices, Inc.

In [42]:
Tech = 'AMD'
# mean
mu = All_returns.mean()[Tech]
# standard deviation
sigma = All_returns.std()[Tech]
# Analysis
Monte_Carlo_Analysis(Tech, mu = mu, sigma = sigma)
Out[42]:
High Low Open Close Volume Adj Close Moving Ave. 10 days Moving Ave. 20 days Moving Ave. 60 days
Date
2018-11-28 21.879999 20.180000 21.820000 21.340000 134425300.0 21.340000 NaN NaN NaN
2018-11-29 21.610001 20.730000 21.190001 21.430000 79853700.0 21.430000 NaN NaN NaN
2018-11-30 21.360001 20.520000 21.299999 21.299999 82370700.0 21.299999 NaN NaN NaN
2018-12-03 23.750000 22.370001 22.480000 23.709999 139607400.0 23.709999 NaN NaN NaN
2018-12-04 23.420000 21.070000 23.350000 21.120001 127392900.0 21.120001 NaN NaN NaN
... ... ... ... ... ... ... ... ... ...
2019-11-21 40.709999 38.639999 40.419998 39.520000 88069400.0 39.520000 38.541000 36.572000 32.306667
2019-11-22 39.889999 38.189999 39.360001 39.150002 56931900.0 39.150002 38.827000 36.894000 32.435000
2019-11-25 40.169998 39.490002 39.500000 39.790001 45769500.0 39.790001 39.175000 37.199000 32.574000
2019-11-26 39.480000 38.810001 39.299999 38.990002 43603300.0 38.990002 39.403001 37.497001 32.708833
2019-11-27 39.759998 39.070000 39.459999 39.410000 33630100.0 39.410000 39.592001 37.811000 32.849833

252 rows × 9 columns

In [43]:
Simulations = Final_price_distribution_simulations(Tech, mu = mu, sigma = sigma)
|#########################################################################|100%
In [44]:
Final_price_distribution_plot(Simulations, Tech)

It seems that AMD's overall price is increasing!

Apple Inc.

In [45]:
Tech = 'AAPL'
# mean
mu = All_returns.mean()[Tech]
# standard deviation
sigma = All_returns.std()[Tech]
# Analysis
Monte_Carlo_Analysis(Tech, mu = mu, sigma = sigma)
Out[45]:
High Low Open Close Volume Adj Close Moving Ave. 10 days Moving Ave. 20 days Moving Ave. 60 days
Date
2018-11-28 181.289993 174.929993 176.729996 180.940002 46062500.0 178.261627 NaN NaN NaN
2018-11-29 182.800003 177.699997 182.660004 179.550003 41770000.0 176.892197 NaN NaN NaN
2018-11-30 180.330002 177.029999 180.289993 178.580002 39531500.0 175.936554 NaN NaN NaN
2018-12-03 184.940002 181.210007 184.460007 184.820007 40802500.0 182.084183 NaN NaN NaN
2018-12-04 182.389999 176.270004 180.949997 176.690002 41344300.0 174.074539 NaN NaN NaN
... ... ... ... ... ... ... ... ... ...
2019-11-21 264.010010 261.179993 263.690002 262.010010 30348800.0 262.010010 263.576007 257.352966 234.642410
2019-11-22 263.179993 260.839996 262.589996 261.779999 16331300.0 261.779999 263.740005 258.149870 235.532337
2019-11-25 266.440002 262.519989 262.709991 266.369995 21005100.0 266.369995 264.157004 259.053143 236.503250
2019-11-26 267.160004 262.500000 266.940002 264.290009 26301900.0 264.290009 264.390005 260.139556 237.490012
2019-11-27 267.980011 265.309998 265.579987 267.839996 16308900.0 267.839996 264.727005 261.404964 238.477948

252 rows × 9 columns

In [46]:
Simulations = Final_price_distribution_simulations(Tech, mu = mu, sigma = sigma)
|#########################################################################|100%
In [47]:
Final_price_distribution_plot(Simulations, Tech)

It seems that Apple's overall price is increasing!

Microsoft Corporation

In [48]:
Tech = 'MSFT'
# mean
mu = All_returns.mean()[Tech]
# standard deviation
sigma = All_returns.std()[Tech]
# Analysis
Monte_Carlo_Analysis(Tech, mu = mu, sigma = sigma)
Out[48]:
High Low Open Close Volume Adj Close Moving Ave. 10 days Moving Ave. 20 days Moving Ave. 60 days
Date
2018-11-28 111.330002 107.860001 107.889999 111.120003 46788500.0 109.500916 NaN NaN NaN
2018-11-29 111.120003 109.029999 110.330002 110.190002 28123200.0 108.584465 NaN NaN NaN
2018-11-30 110.970001 109.360001 110.699997 110.889999 33665600.0 109.274261 NaN NaN NaN
2018-12-03 113.419998 110.730003 113.000000 112.089996 34732800.0 110.456779 NaN NaN NaN
2018-12-04 112.639999 108.209999 111.940002 108.519997 45197000.0 106.938789 NaN NaN NaN
... ... ... ... ... ... ... ... ... ...
2019-11-21 149.800003 148.500000 149.399994 149.479996 18576100.0 149.479996 148.029071 145.609914 140.304875
2019-11-22 150.300003 148.820007 150.070007 149.589996 15901800.0 149.589996 148.441568 146.076777 140.503849
2019-11-25 151.350006 149.919998 150.000000 151.229996 22420900.0 151.229996 149.003116 146.453226 140.734474
2019-11-26 152.419998 151.320007 151.360001 152.029999 24620100.0 152.029999 149.548990 146.937444 141.008663
2019-11-27 152.500000 151.520004 152.330002 152.320007 15184400.0 152.320007 150.099947 147.347464 141.261275

252 rows × 9 columns

In [49]:
Simulations = Final_price_distribution_simulations(Tech, mu = mu, sigma = sigma)
|#########################################################################|100%
In [50]:
Final_price_distribution_plot(Simulations, Tech)

It seems that Microsoft's overall price is increasing!